package org.example.guava;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;

/**
 * @Classname 自动加载
 * @Description Cache的get方法有两个参数，第一个参数是要从Cache中获取记录的key，第二个记录是一个Callable对象。
 * 当缓存中已经存在key对应的记录时，get方法直接返回key对应的记录。如果缓存中不包含key对应的记录，
 * Guava会启动一个线程执行Callable对象中的call方法，call方法的返回值会作为key对应的值被存储到缓存中，并且被get方法返回。
 * 下面是一个多线程的例子
 * 这段代码中有两个线程共享同一个Cache对象，两个线程同时调用get方法获取同一个key对应的记录。由于key对应的记录不存在，
 * 所以两个线程都在get方法处阻塞。此处在call方法中调用Thread.sleep(1000)模拟程序从外存加载数据的时间消耗。
 * 从结果中可以看出，虽然是两个线程同时调用get方法，但只有一个get方法中的Callable会被执行(没有打印出load2)。
 * Guava可以保证当有多个线程同时访问Cache中的一个key时，如果key对应的记录不存在，
 * Guava只会启动一个线程执行get方法中Callable参数对应的任务加载数据存到缓存。
 * 当加载完数据后，任何线程中的get方法都会获取到key对应的值。
 * @Date 2020/12/21 11:34 上午
 * @Created by xiangjd
 */
public class Test {

    private static  Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize(3).build();

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thead1");
                try {
                    String value = cache.get("key", new Callable<String>() {
                        @Override
                        public String call() throws Exception {
                            System.out.println("load1");
                            Thread.sleep(1000);
                            return "auto load by Callable";
                        }
                    });
                    System.out.println("thread1" + value);
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread2");
                try {
                    String value = cache.get("key", new Callable<String>() {
                        @Override
                        public String call() throws Exception {
                            System.out.println("load2");
                            Thread.sleep(1000);
                            return "auto load by Callable";
                        }
                    });
                    System.out.println("thread2" + value);
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
